#ifndef __CZF_VAR_ARRAY_T_H__
#define __CZF_VAR_ARRAY_T_H__

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

template <class T> class CVarArrayT
{
public:
   CVarArrayT(unsigned int nInitCount)
   {
      m_nCount = nInitCount;
      if (nInitCount > 0) {
         m_pArray = new T[nInitCount];
         if (!m_pArray) {
            fprintf (stderr, "%s, %d, CVarArrayT, cannot allocate memory.\n", __FILE__, __LINE__);
            m_nCount = 0;
            return;
         }
      } else {
         m_pArray = NULL;
      }
   }
   virtual ~CVarArrayT()
   {
      if (m_pArray) {
         delete[] m_pArray;
      }
   }

   // Returns 0 on success. 
   // -1, if no memory.
   int Resize(unsigned int nCount)
   {
      if (m_nCount == nCount) {
         return 0;
      }
      
      int nMin = m_nCount > nCount ? nCount : m_nCount;

      if (nCount > 0) {
         T* pTmp = new T [nCount];
         if (!pTmp) {
            fprintf (stderr, "%s, %d, Resize, cannot allocate memory.\n", __FILE__, __LINE__);
            return -1;
         }
         if (m_pArray) {
            memcpy(pTmp, m_pArray, sizeof(T)*nMin);
            delete [] m_pArray;
         } else {
            /* !m_pArray */
            assert (m_nCount == 0);
         }
         m_pArray = pTmp;  
         m_nCount = nCount;
         return 0;
      }
      /* nCount == 0 */
      assert (nCount == 0);
      if (m_pArray) {
         delete [] m_pArray;
         m_pArray = NULL;
         m_nCount = 0;
      } 
      /* !m_pArray */
      assert (m_nCount == 0);
      return 0;
   }
   
   unsigned int GetCount()
   {
      return m_nCount;
   }

   void Remove(unsigned int nStartIdx, unsigned int nEndIdx)
   {
      assert (nStartIdx < m_nCount && nEndIdx < m_nCount);
      assert (m_pArray);

      if (nStartIdx > nEndIdx) {
          int tmp = nEndIdx;
          nEndIdx = nStartIdx;
          nStartIdx = tmp;
      }
      
      memmove(m_pArray+nStartIdx, (m_pArray+nEndIdx+1), sizeof(T)*(m_nCount-nEndIdx-1));
      return;
   }
      
   void InsertAt (unsigned int nIdx, unsigned int size, const T* p)
   {
      assert (nIdx < m_nCount);
      assert (nIdx + size <= m_nCount);
      assert (m_pArray);

      memmove(m_pArray+nIdx+size, m_pArray+nIdx, sizeof(T)*(m_nCount-nIdx-size));
      memcpy (m_pArray+nIdx, p, sizeof(T)*size);
      return;
   }

   T* Detach()
   {
      T* pArray = m_pArray;
      m_pArray = NULL;
      m_nCount = 0;
      return pArray;   
   }
        
   T& operator [](unsigned int nIdx)
   {
      assert (nIdx < m_nCount);
      assert (m_pArray);
      
      return (m_pArray[nIdx]);
   }
   
   T* GetArrayPtr()
   {
      return m_pArray;
   }
   
   void Clear ()
   {
      if (m_pArray) {
         delete [] m_pArray;
         m_pArray = NULL;
      }
      m_nCount = 0;
   }

protected:
   unsigned int m_nCount;
   T* m_pArray;   
};
#endif // __CZF_VAR_ARRAY_H__
